<?php
/**
 * Created by PhpStorm.
 * User: whwyy
 * Date: 2018/4/24 0024
 * Time: 19:39
 */

namespace BeReborn\Http;

use BeReborn;
use BeReborn\Service\Common\ServerRequest;
use Swoole\Coroutine;
use BeReborn\Base\Component;
use BeReborn\Core\ArrayAccess;
use BeReborn\Core\JSON;
use BeReborn\Error\Logger;
use BeReborn\Http\Formatter\HtmlFormatter;
use BeReborn\Http\Formatter\JsonFormatter;
use BeReborn\Http\Formatter\XmlFormatter;
use Exception;
use Swoole\WebSocket\Server;
use Swoole\Http\Response as SResponse;

/**
 * Class Response
 * @package BeReborn\Http
 */
class Response extends Component
{

	const JSON = 'json';
	const XML = 'xml';
	const HTML = 'html';

	/** @var string */
	public $format = null;

	/** @var int */
	public $statusCode = 200;

	/** @var SResponse */
	public $response;
	public $isWebSocket = false;
	public $headers = [];

	private $startTime = 0;

	public $fd = 0;

	/**
	 * @param $format
	 * @return $this
	 */
	public function setFormat($format)
	{
		$this->format = $format;
		return $this;
	}

	/**
	 * 清理无用数据
	 */
	public function clear()
	{
		$this->fd = 0;
		$this->isWebSocket = false;
		$this->format = null;
	}

	/**
	 * @return string
	 */
	public function getContentType()
	{
		if ($this->format == null || $this->format == static::JSON) {
			return 'application/json;charset=utf-8';
		} else if ($this->format == static::XML) {
			return 'application/xml;charset=utf-8';
		} else {
			return 'text/html;charset=utf-8';
		}
	}

	/**
	 * @return mixed
	 * @throws Exception
	 */
	public function sender()
	{
		return $this->send(func_get_args());
	}

	/**
	 * @param $key
	 * @param $value
	 */
	public function addHeader($key, $value)
	{
		$response = Context::getResponse();
		$response->header($key, $value);
	}

	/**
	 * @param $context
	 * @param $statusCode
	 * @return bool
	 * @throws Exception
	 */
	public function send($context = '', $statusCode = 200)
	{
		$sendData = $this->parseData($context);
		if (($response = Context::getResponse()) instanceof SResponse) {
			Coroutine::defer([$this, 'clear']);
			return $this->sendData($response, $sendData, $statusCode);
		} else {
			return $this->printResult($sendData);
		}
	}

	/**
	 * @param $context
	 * @return mixed
	 * @throws Exception
	 */
	private function parseData($context)
	{
		if ($this->format == static::JSON) {
			$config['class'] = JsonFormatter::class;
		} else if ($this->format == static::XML) {
			$config['class'] = XmlFormatter::class;
		} else {
			$config['class'] = HtmlFormatter::class;
		}
		$formatter = BeReborn::createObject($config);
		return $formatter->send($context)->getData();
	}

	/**
	 * @param $result
	 * @return string
	 * @throws Exception
	 */
	private function printResult($result)
	{
		if (!is_string($result)) {
			$result = ArrayAccess::toArray($result);
			if (is_array($result)) {
				$result = JSON::encode($result);
			}
		}

		$string = 'Command Result: ' . PHP_EOL;
		$string .= empty($result) ? 'success!' : $result . PHP_EOL;
		$string .= 'Command Success!' . PHP_EOL;
		echo $string;

		fire('CONSOLE_END');
		return 'ok';
	}

	/**
	 * @param $response
	 * @param $sendData
	 * @param $status
	 * @return mixed
	 */
	private function sendData($response, $sendData, $status)
	{
		/** @var SResponse $response */
		$server = BeReborn::getWebSocket();
		if(!$server->exist($response->fd)){
			return null;
		}
		$response->status($status);
		$response->header('Content-Type', $this->getContentType());
		$response->header('Access-Control-Allow-Origin', '*');
		$response->header('Run-Time', $this->getRuntime());
		return $response->end($sendData);
	}

	/**
	 * @param $url
	 * @param array $param
	 * @return int
	 */
	public function redirect($url, array $param = [])
	{
		if (!empty($param)) {
			$url .= '?' . http_build_query($param);
		}

		$url = ltrim($url, '/');
		if (!preg_match('/^http/', $url)) {
			$url = '/' . $url;
		}

		return redirect($url);
	}

	/**
	 * @param $response
	 * @return mixed
	 * @throws Exception
	 */
	public static function setResponse($response)
	{
		Context::setResponse($response);

		$ciResponse = BeReborn::$app->getResponse();
		$ciResponse->startTime = microtime(true);
		$ciResponse->format = self::JSON;
		return $ciResponse;
	}


	/**
	 * @throws Exception
	 */
	public function sendNotFind()
	{
		$this->format = static::HTML;
		$this->send('', 404);
	}

	/**
	 * @return string
	 */
	public function getRuntime()
	{
		return sprintf('%.5f', microtime(TRUE) - $this->startTime);
	}

}
